﻿using MiniExcelLibs;
using S7.Net;
using ScottPlot.Plottable;
using ScottPlot;
using Sunny.UI;
using SunnyScopplotS7netplus;
using SunnyUIPlcConnect.Models;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using DevExpress.Data.Filtering.Helpers;

namespace SunnyUIPlcConnect
{
    public partial class Form1 : UIForm
    {

        private DataGetModel _model;
        private List<DataGetModel> dataGetModels;
        private S7Helper PLC;
        private CancellationTokenSource _ctsWrite = new CancellationTokenSource();
        private CancellationTokenSource _ctsReflash = new CancellationTokenSource();
        private CancellationTokenSource _ctsDataCopy = new CancellationTokenSource();

        private Task _taskWrite;
        private Task _taskReFlash;
        private Task _taskDataCopy;

        private bool _acqEnable = false;
        private bool _mockEnable = false;
        public Form1()
        {
            InitializeComponent();
            InitData();
            InitCycle();
            InitScottPlot();
            ScottPlotLiveUpdate();
            ScottPlotThread();
        }

        private void ScottPlotThread()
        {
            _taskDataCopy = Task.Run(() => DataCopyTask(_ctsDataCopy.Token), _ctsDataCopy.Token);
            _taskReFlash = Task.Run(() => ScottPlotRefreshTask(_ctsReflash.Token), _ctsReflash.Token);
        }



        private void ScottPlotLiveUpdate()
        {
            double[] liveData = new double[400];
            DataGen.Electrocardiogram ecg = new DataGen.Electrocardiogram();
            Stopwatch sw = Stopwatch.StartNew();
            VLine vline;
        }

        double[] liveData = new double[400];
        DataGen.Electrocardiogram ecg = new DataGen.Electrocardiogram();
        Stopwatch sw = Stopwatch.StartNew();
        VLine vline;
        private void InitScottPlot()
        {
            // plot the data array only once and we can updates its values later
            formsPlot1.Plot.AddSignal(liveData);
            formsPlot1.Plot.SetAxisLimitsY(20, 30);
            formsPlot1.Plot.AxisAutoX(margin: 0);


            // plot a red vertical line and save it so we can move it later
            vline = formsPlot1.Plot.AddVerticalLine(0, Color.Red, 2);

            // customize styling
            formsPlot1.Plot.Title("Electrocardiogram Strip Chart");
            formsPlot1.Plot.YLabel("Potential (mV)");
            formsPlot1.Plot.XLabel("Time (seconds)");
            formsPlot1.Plot.Grid(false);

            Closed += (sender, args) =>
            {
                //timerUpdateData?.Stop();
                //timerRender?.Stop();
            };

        }

        private void InitCycle()
        {

            var thread = new Thread(() =>
            {
                while (true)
                {
                    try
                    {
                        if (PLC != null && PLC.Connected)
                        {
                            var TempValue = PLC.ReadSingleData_Float(1, 2, 4, PlcDataType.Float);
                            Invoke(new Action(() =>
                                {
                                    S7IndoorTemp.Value = TempValue;
                                }));


                        }
                        Thread.Sleep(500);
                    }
                    catch (Exception e)
                    {
                        HLog.Error("读取出错", e);
                    }
                }
            }

            );
            thread.Start();


        }

        private void InitData()
        {
            try
            {
                string iniFilePath = AppDomain.CurrentDomain.BaseDirectory + "config.ini";
                IniFile ini = new IniFile(iniFilePath);
                string DataGet = ini.ReadString("Setup", "DataGetPath", "");

                using (var stream = File.OpenRead(AppDomain.CurrentDomain.BaseDirectory + DataGet))
                {
                    dataGetModels = stream.Query<DataGetModel>().ToList();
                    uiDataGridViewPLC.DataSource = dataGetModels;
                }
            }
            catch (Exception e)
            {
                MessageBox.Show(e.Message);
            }

        }

        private void SwitchConnect_ActiveChanged(object sender, EventArgs e)
        {
            try
            {
                if (SwitchConnect.Active)
                {
                    PLC = new S7Helper("S71500", S7IP.Text);
                    bool status = PLC.ConnectPLC(S7Port.IntValue, (short)S7Rack.Value, (short)S7Slot.Value);
                    S7Status.State = status ? UILightState.On : UILightState.Off;


                }
                else
                {
                    if (PLC != null)
                    {
                        PLC.DisconnectPLC();
                        S7Status.State = UILightState.Off;
                    }

                }
            }
            catch (Exception m)
            {

                MessageBox.Show(m.Message);
            }
        }

        private void uiButton2_Click(object sender, EventArgs e)
        {


            if (!_acqEnable && PLC != null && PLC.Connected)
            {
                sw.Stop();
                _ctsDataCopy = new CancellationTokenSource();
                _ctsReflash = new CancellationTokenSource();
                _taskDataCopy = Task.Run(() => DataCopyTask(_ctsDataCopy.Token), _ctsDataCopy.Token);
                _taskReFlash = Task.Run(() => ScottPlotRefreshTask(_ctsReflash.Token), _ctsReflash.Token);
                _acqEnable = true;
                uiButton2.Text = "停止采集";
            }
            else
            {
                sw.Start();
                _ctsDataCopy?.Cancel();
                _ctsReflash?.Cancel();
                _acqEnable = false;
                uiButton2.Text = "采集数据";
            }
        }
        int nextValueIndex = -1;


        private async Task ScottPlotRefreshTask(CancellationToken cts)
        {
            while (!cts.IsCancellationRequested)
            {
                Invoke(new Action(() =>
                {
                    //formsPlot1.Plot.AxisAuto();
                    //formsPlot1.Plot.AxisAutoY(margin: 0);
                    //formsPlot1.Plot.AxisAutoX(margin: 0);
                    formsPlot1.Refresh();

                }));
                await Task.Delay(100, cts);
            }
        }
        private async Task DataCopyTask(CancellationToken cts)
        {

            while (_acqEnable && !cts.IsCancellationRequested)
            {
                try
                {
                    double nextValue = 0;
                    if (PLC != null && PLC.Connected && _model.Type == "Float")
                    {

                        nextValue = PLC.ReadSingleData_Float(1, _model.Address, 4, PlcDataType.Float);
                    }

                    if (checkBoxRoll.Checked)
                    {
                        // "roll" new values over old values like a traditional ECG machine
                        nextValueIndex = (nextValueIndex < liveData.Length - 1) ? nextValueIndex + 1 : 0;
                        liveData[nextValueIndex] = nextValue;
                        vline.IsVisible = true;
                        vline.X = nextValueIndex;
                    }
                    else
                    {
                        // "scroll" the whole chart to the left
                        Array.Copy(liveData, 1, liveData, 0, liveData.Length - 1);
                        liveData[liveData.Length - 1] = nextValue;
                        vline.IsVisible = false;
                    }

                    await Task.Delay(100, cts);
                }
                catch (Exception e)
                {
                    HLog.Error("数据赋值出错", e);
                }
            }


        }



        private void checkBoxRoll_CheckedChanged(object sender, EventArgs e)
        {
            // clear old data values
            for (int i = 0; i < liveData.Length; i++)
                liveData[i] = 0;
        }

        private void uiButton1_Click(object sender, EventArgs e)
        {
            _ctsWrite?.Cancel();
            _ctsWrite = new CancellationTokenSource();
            if (!_mockEnable && PLC != null && PLC.Connected)
            {
                _taskWrite = Task.Run(() => MockDataWrite(_ctsWrite.Token), _ctsWrite.Token);
                _mockEnable = true;
                uiButton1.Text = "停止模拟";
            }
            else
            {
                _ctsWrite?.Cancel();
                uiButton1.Text = "模拟数据";
                _mockEnable = false;
            }
        }

        private async Task MockDataWrite(CancellationToken cts)
        {
            try
            {
                while (PLC.Connected && !cts.IsCancellationRequested)
                {

                    Random rnd = new Random();
                    float WriteNum = (30 - 26) * (float)rnd.NextDouble() + 26;
                    if (uiDataGridViewPLC.SelectedIndex >= 0 && _model.Type == "Float")
                    {
                        PLC.WriteSingleData_Float(1, _model.Address, WriteNum, 4, PlcDataType.Float);
                    }
                    await Task.Delay(100, cts);
                }
            }
            catch (Exception e)
            {
                HLog.Error("写入错误", e);
            }

        }

        private void uiDataGridViewPLC_SelectIndexChange(object sender, int index)
        {

            if (index >= 0)
            {
                nextValueIndex = 0;
                for (int i = 0; i < liveData.Length; i++)
                    liveData[i] = 0;
                _model = uiDataGridViewPLC.Rows[index].DataBoundItem as DataGetModel;
                formsPlot1.Plot.Title($"{_model.Describe}");

            }
            //MessageBox.Show($"{index}");
        }
    }
}
